/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   VariablesIDE.cs
 * CreateData   :   2023/10/24 19:38:50
 * UnityVersion :   2021.3.30f1c1
 * Description  :   Hotfix ECS 数据生成组件
************************************************/
#pragma warning disable CS0414

using Sirenix.OdinInspector;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Reflection;
using Unity.VisualScripting;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Main
{
    [ExecuteAlways]
    [HideMonoScript]
    [DisallowMultipleComponent]
    [RequireComponent(typeof(Variables))]
    public class VariablesIDE : MonoBehaviour
    {
        private Variables _variables;
        private void Awake()
        {
            _variables = GetComponent<Variables>();
        }
#if UNITY_EDITOR
        [SerializeField, ReadOnly, HideLabel, HorizontalGroup("Script")]
        private TextAsset scriptFile;

        [HorizontalGroup("Script", 40), Button("定位"), EnableIf("@this.scriptFile")]
        private void PingScriptFile()
        {
            if (scriptFile)
            {
                EditorGUIUtility.PingObject(scriptFile);
            }
        }

        [HorizontalGroup("Script", 80), Button("生成脚本"), EnableIf("@this.isError==false&&this.ComponentName!=\"Null\"")]
        private void GenerateScript()
        {
            string code = CodeStr();
            if (scriptFile)
            {
                if (ComponentName != scriptFile.name)
                {
                    if (!EditorUtility.DisplayDialog("提示", "脚本名和文件名不匹配，是否继续", "OK", "Cancel"))
                    {
                        return;
                    }
                }
                // 直接写入文件
                string assetPath = AssetDatabase.GetAssetPath(scriptFile);
                string filePath = PathConfig.AbsolutePath + assetPath;
                File.WriteAllText(filePath, code, Encoding.UTF8);
                // 重命名 防止名称不一致
                AssetDatabase.RenameAsset(assetPath, ComponentName);
                AssetDatabase.Refresh();
            }
            else
            {
                string filePath = PathConfig.ComponentDataJsPath + ComponentName + ".cs";
                string absolutePath = PathConfig.AbsolutePath + filePath;
                // 判断是否包含这个文件
                if (File.Exists(filePath))
                {
                    if (EditorUtility.DisplayDialog("提示", "该文件已存在 是否覆盖！", "OK", "Cancel"))
                    {
                        File.WriteAllText(absolutePath, code, Encoding.UTF8);
                        AssetDatabase.ImportAsset(filePath);
                        scriptFile = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);
                        AssetDatabase.SaveAssets();
                        AssetDatabase.Refresh();
                    }
                }
                else
                {
                    // 判断是否包含程序集
                    string dllPath = PathConfig.AbsolutePath + PathConfig.CodeDllPath + "hotfix.dll.bytes";
                    Assembly assembly = Assembly.LoadFile(dllPath);
                    foreach (var type in assembly.GetTypes())
                    {
                        if (type.Name.Equals(ComponentName))
                        {
                            // 程序集中
                            // 包含这个类型
                            if (EditorUtility.DisplayDialog("提示", "程序集中已包含该类型\n是否继续创建脚本！", "OK", "Cancel"))
                            {
                                File.WriteAllText(absolutePath, code, Encoding.UTF8);
                                AssetDatabase.ImportAsset(filePath);
                                scriptFile = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);
                                AssetDatabase.SaveAssets();
                                AssetDatabase.Refresh();
                                Debug.Log("执行操作");
                            }
                            else
                            {
                                Debug.Log("取消操作");
                            }
                            return;
                        }
                    }
                    // 程序集中不包含这个类型
                    File.WriteAllText(absolutePath, code, Encoding.UTF8);
                    AssetDatabase.ImportAsset(filePath);
                    scriptFile = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }
            }
        }
#endif
        [HorizontalGroup, LabelText("脚本名:"), LabelWidth(50), Delayed, OnValueChanged("OnComponentNameChange")]
        public string ComponentName = "Null";
        [HorizontalGroup, LabelText("描述:"), LabelWidth(40)]
        public string Description;
#if UNITY_EDITOR
        [HideInInspector]
        private bool isError = false;
        private string infoTip = "字段不能为空";
        [InfoBox("$infoTip", InfoMessageType.Error, "isError")]
        [Button("预览")]
        private void Preview()
        {
            GenerateScriptPreviewWindow.ShowWindow(CodeStr());
        }
        private void Check()
        {
            string fieldName = "";
            object fieldValue = null;
            foreach (var item in this)
            {
                fieldName = item.name;
                fieldValue = item.value;
                if (string.IsNullOrWhiteSpace(fieldName))
                {
                    isError = true;
                    infoTip = "Variables 组件中字段名称空白！";
                    return;
                }
                else if (fieldValue == null)
                {
                    isError = true;
                    infoTip = $"Variables 组件中{fieldName}值为空！";
                    return;
                }
            }
            isError = false;
        }
        // 字段转 代码
        private string CodeStr()
        {
            string tab = "                    ";
            string blank = " ";
            string newLine = "\n";
            string Modifier = "public";
            string end = ";";
            StringBuilder script = new StringBuilder();
            script.Append(newLine + tab + newLine);
            foreach (var item in this)
            {
                string fieldName = item.name;
                Type type = Type.GetType(item.typeHandle.Identification);
                string typeStr = type.ToString();
                if (type.IsGenericType)
                {
                    // ^([a-zA-Z.]*)`(\d)\[([a-zA-Z0-9.,]*)\]
                    string pattern = @"^([a-zA-Z.]*)`(\d)\[([a-zA-Z0-9.,]*)\]";
                    Match match = Regex.Match(typeStr, pattern);
                    if (match.Success && match.Groups.Count == 4)
                    {
                        string group1 = match.Groups[1].Value;
                        string group3 = match.Groups[3].Value;
                        typeStr = $"{group1}<{group3}>";
                    }
                    else
                    {
                        Debug.LogError("类型错误，不在解析范围内！");
                    }
                }
                script.Append(tab + Modifier + blank + typeStr + blank + fieldName + end + newLine + newLine);
            }
            // 获取文件
            string content = File.ReadAllText(PathConfig.TemplatesPath + "Component.txt");
            // 替换脚本名
            content = content.Replace("#SCRIPTNAME#", ComponentName);
            // 替换描述
            content = content.Replace("#DESCRIPTION#", Description);
            // 替换内容
            content = content.Replace("#SCRIPTCONTENT#", script.ToString());
            return content;
        }
        private void OnComponentNameChange()
        {
            if (!Regex.IsMatch(ComponentName, @"^[a-zA-Z_][a-zA-Z0-9_]*$"))
            {
                ComponentName = "Null";
            }
        }
        private void Update()
        {
            Check();
        }
        [OnInspectorInit]
        private void OnInspectorInit()
        {
            Check();
        }
#endif
        #region Utility
        /// <summary>
        /// 获取 Variables 组件字段值
        /// </summary>
        /// <typeparam name="T">字段类型</typeparam>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public T Get<T>(string fieldName)
        {
            if (Contains(fieldName))
            {
                return _variables.declarations.Get<T>(fieldName);
            }
            else
            {
                return default(T);
            }
        }
        /// <summary>
        /// 获取 Variables 组件字段值
        /// </summary>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public object Get(string fieldName)
        {
            if (Contains(fieldName))
            {
                return _variables.declarations.Get(fieldName);
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 是否包内 fieldName 字段
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public bool Contains(string fieldName)
        {
            return _variables.declarations.IsDefined(fieldName);
        }
        /// <summary>
        /// 获取指定字段类型
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public Type GetFieldType(string fieldName)
        {
            if (Contains(fieldName))
            {
                return _variables.declarations.Get(fieldName).GetType();
            }
            return null;
        }
        /// <summary>
        /// 迭代
        /// </summary>
        public IEnumerator<VariableDeclaration> GetEnumerator()
        {
            if (_variables == null)
            {
                _variables = GetComponent<Variables>();
            }
            return _variables.declarations.GetEnumerator();
        }
        #endregion
    }
}
